using System;
using System.IO.Ports;
using System.Threading.Tasks;
using System.Text;
using System.Threading;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace ZGL.Api.Services
{
    public class SerialPortService : IHostedService, IDisposable
    {
        private readonly SerialPort _sendPort;  // COM3用于发送
        private readonly SerialPort _receivePort; // COM4用于接收
        private readonly object _lockObject = new object();
        private readonly ILogger<SerialPortService> _logger;
        private bool _isDisposed;
        private const int MaxRetryAttempts = 3;
        private const int RetryDelayMilliseconds = 1000;

        public SerialPortService(ILogger<SerialPortService> logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            // 初始化发送端口 (COM3)
            _sendPort = new SerialPort("COM3")
            {
                BaudRate = 115200,
                DataBits = 8,
                StopBits = StopBits.One,
                Parity = Parity.None,
                ReadTimeout = 1000,
                WriteTimeout = 1000
            };

            // 初始化接收端口 (COM4)
            _receivePort = new SerialPort("COM4")
            {
                BaudRate = 115200,
                DataBits = 8,
                StopBits = StopBits.One,
                Parity = Parity.None,
                ReadTimeout = 1000,
                WriteTimeout = 1000
            };
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Starting SerialPortService...");
            await OpenPortsAsync();
            _logger.LogInformation("SerialPortService started successfully");
        }

        public async Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stopping SerialPortService...");
            await ClosePortsAsync();
            _logger.LogInformation("SerialPortService stopped successfully");
        }

        private async Task OpenPortsAsync()
        {
            for (int attempt = 0; attempt < MaxRetryAttempts; attempt++)
            {
                try
                {
                    if (!_sendPort.IsOpen)
                    {
                        _sendPort.Open();
                        _logger.LogInformation("Send port (COM3) opened successfully");
                    }

                    if (!_receivePort.IsOpen)
                    {
                        _receivePort.Open();
                        _logger.LogInformation("Receive port (COM4) opened successfully");
                    }
                    return;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"Failed to open serial ports (attempt {attempt + 1}/{MaxRetryAttempts})");
                    if (attempt < MaxRetryAttempts - 1)
                    {
                        await Task.Delay(RetryDelayMilliseconds);
                    }
                }
            }
        }

        private async Task ClosePortsAsync()
        {
            try
            {
                if (_sendPort.IsOpen)
                {
                    _sendPort.Close();
                }

                if (_receivePort.IsOpen)
                {
                    _receivePort.Close();
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while closing serial ports");
                throw;
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        public async Task<bool> SendDataAsync(byte[] data)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(SerialPortService));

            try
            {
                await Task.Run(() =>
                {
                    lock (_lockObject)
                    {
                        if (!_sendPort.IsOpen)
                        {
                            _sendPort.Open();
                        }

                        _sendPort.Write(data, 0, data.Length);
                        _logger.LogDebug($"Data sent successfully: {BitConverter.ToString(data)}");
                    }
                });
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to send data");
                throw new Exception($"Failed to send data: {ex.Message}");
            }
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        public async Task<byte[]> ReceiveDataAsync(int timeout = 1000)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(SerialPortService));

            try
            {
                return await Task.Run(() =>
                {
                    lock (_lockObject)
                    {
                        if (!_receivePort.IsOpen)
                        {
                            _receivePort.Open();
                        }

                        _receivePort.ReadTimeout = timeout;

                        var buffer = new byte[1024];
                        int bytesRead = _receivePort.Read(buffer, 0, buffer.Length);

                        if (bytesRead > 0)
                        {
                            var data = new byte[bytesRead];
                            Array.Copy(buffer, data, bytesRead);
                            _logger.LogDebug($"Data received successfully: {BitConverter.ToString(data)}");
                            return data;
                        }

                        return null;
                    }
                });
            }
            catch (TimeoutException)
            {
                _logger.LogWarning("Timeout while receiving data");
                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to receive data");
                throw new Exception($"Failed to receive data: {ex.Message}");
            }
        }

        /// <summary>
        /// 发送并等待响应
        /// </summary>
        public async Task<byte[]> SendAndReceiveAsync(byte[] data, int timeout = 1000)
        {
            if (_isDisposed)
                throw new ObjectDisposedException(nameof(SerialPortService));

            try
            {
                await SendDataAsync(data);
                return await ReceiveDataAsync(timeout);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to send and receive data");
                throw new Exception($"Failed to send and receive data: {ex.Message}");
            }
        }

        /// <summary>
        /// 检查端口状态
        /// </summary>
        public (bool SendPortStatus, bool ReceivePortStatus) GetPortStatus()
        {
            return (_sendPort.IsOpen, _receivePort.IsOpen);
        }

        /// <summary>
        /// 重新打开端口
        /// </summary>
        public async Task ReopenPortsAsync()
        {
            try
            {
                await Task.Run(() =>
                {
                    lock (_lockObject)
                    {
                        if (_sendPort.IsOpen)
                        {
                            _sendPort.Close();
                        }
                        if (_receivePort.IsOpen)
                        {
                            _receivePort.Close();
                        }
                    }
                });

                await OpenPortsAsync();
                _logger.LogInformation("Ports reopened successfully");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to reopen ports");
                throw new Exception($"Failed to reopen ports: {ex.Message}");
            }
        }

        public void Dispose()
        {
            if (!_isDisposed)
            {
                _isDisposed = true;
                try
                {
                    if (_sendPort.IsOpen)
                    {
                        _sendPort.Close();
                    }
                    if (_receivePort.IsOpen)
                    {
                        _receivePort.Close();
                    }
                    _sendPort.Dispose();
                    _receivePort.Dispose();
                    _logger.LogInformation("SerialPortService disposed successfully");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error while disposing SerialPortService");
                }
            }
        }

        internal void ReopenPorts()
        {
            throw new NotImplementedException();
        }
    }
} 